package mk.jug.academy.service;

import mk.jug.academy.model.Comment;
import mk.jug.academy.model.CommentStatus;
import mk.jug.academy.model.Content;
import mk.jug.academy.model.Lecturer;
import mk.jug.academy.model.Page;
import mk.jug.academy.testing.bdd.IntegrationBehavior;
import mk.jug.academy.testing.factory.CommentTestFactory;
import mk.jug.academy.testing.factory.ContentTestFactory;
import mk.jug.academy.testing.factory.LecturerTestFactory;
import mk.jug.academy.testing.util.TestHelper;

import org.springframework.beans.factory.annotation.Autowired;

import com.googlecode.instinct.marker.annotate.Specification;
import com.googlecode.instinct.marker.annotate.Specification.SpecificationState;
import com.googlecode.instinct.marker.annotate.Subject;

/**
 * An integration test unit targeting the behavior regarding the
 * addition of {@link Comment} and their management.
 *
 * @author Ice.Penov
 */
public class CommentFunctionality extends IntegrationBehavior {
	
	@Autowired private ContentService contentService;
	@Autowired private LecturerService lecturerService;
	@Autowired private CommentService commentService;
	
	@Subject private Comment comment;
	//for paging functionality
	@Subject private Comment comment1;
	@Subject private Comment comment2;
	@Subject private Comment comment3;
	
	@Subject private Lecturer lecturer;
	@Subject private Content content;
	
	@Override
	protected void beforeHook() {
		lecturer = LecturerTestFactory.createLecturer();
		content = ContentTestFactory.createContent();
		comment = CommentTestFactory.createComment();
		comment1 = CommentTestFactory.createComment();
		comment2 = CommentTestFactory.createComment();
		comment3 = CommentTestFactory.createComment();
		
		TestHelper.init(lecturerService);
		TestHelper.init(contentService);
		TestHelper.init(commentService);
	}
	
	/**
	 * User action:
	 * A {@link Comment} is added to a {@link Content}.
	 * 
	 * Expected behavior:
	 * 1. The {@link Comment} is listed as {@link CommentStatus#PUBLISHED}
	 * 2. The count of comments for the {@link Content} is increased
	 */
	@Specification(state = SpecificationState.COMPLETE)
	public void addComment() {
		TestHelper.prepareActiveLecturer(lecturer);
		contentService.save(content, lecturer);
		int prevCount = content.getNumberOfComments();
		commentService.add(comment, content);
		//expectations.
		expect.that(commentService.fetchCommentsForContent(content)).containsItems(comment);
		expect.that(commentService.fetchCommentsForContent(content)).isOfSize(1);
		expect.that(commentService.listActive(1, 2).getItems()).containsItems(comment);
		expect.that(commentService.listActive(1, 2).getItems()).isOfSize(1);
		expect.that(content.getNumberOfComments()).isGreaterThan(prevCount);
	}
	
	/**
	 * User action:
	 * A {@link Comment} is deleted.
	 * 
	 * Expected behavior:
	 * 1. The {@link Comment} is listed as {@link CommentStatus#DELETED}
	 * 2. The count of comments for the {@link Content} is decreased
	 */
	@Specification(state = SpecificationState.COMPLETE)
	public void deleteComment() {
		TestHelper.prepareActiveLecturer(lecturer);
		contentService.save(content, lecturer);
		commentService.add(comment, content);
		int prevCount = content.getNumberOfComments();
		//delete it.
		commentService.delete(comment);
		//expectations.
		expect.that(commentService.fetchCommentsForContent(content)).isEmpty();
		expect.that(commentService.listDeleted(1, 2).getItems()).containsItem(comment);
		expect.that(commentService.listDeleted(1, 2).getItems()).isOfSize(1);
		Content reloaded = contentService.load(content.getId());
		expect.that(reloaded.getNumberOfComments()).isLessThan(prevCount);
	}
	
	/**
	 * User action:
	 * Fetch the comments in a paged manner.
	 * 
	 * Expected behavior:
	 * List the records as expected.
	 */
	@Specification(state = SpecificationState.COMPLETE)
	public void listRecordsUsingPaging() {
		//published records:
		TestHelper.publishContent(lecturer, content);
		TestHelper.addComment(comment1, content);
		TestHelper.addComment(comment2, content);
		TestHelper.addComment(comment3, content);
		//expectations.
		//comments are sorted by most recent.		
		Page<Comment> page1 = commentService.listActive(1, 2);
		Page<Comment> page2 = commentService.listActive(2, 2);
		Page<Comment> page3 = commentService.listActive(3, 2);
		//check size.
		expect.that(page1.getTotalCount()).isEqualTo(3);
		expect.that(page2.getTotalCount()).isEqualTo(3);
		expect.that(page3.getTotalCount()).isEqualTo(3);
		expect.that(page1.getItems()).isOfSize(2);
		expect.that(page2.getItems()).isOfSize(1);
		expect.that(page3.getItems()).isEmpty();
		//check contents of pages.
		expect.that(page1.getItems()).containsItems(comment3, comment2);
		expect.that(page2.getItems()).containsItem(comment1);
		
		//deleted records:
		commentService.delete(comment3);
		//expectations.
		page1 = commentService.listActive(1, 2);
		page2 = commentService.listActive(2, 2);
		expect.that(page1.getItems()).isOfSize(2);
		expect.that(page2.getItems()).isEmpty();
		page1 = commentService.listDeleted(1, 2);
		expect.that(page1.getItems()).isOfSize(1);
		expect.that(page1.getItems()).containsItem(comment3);
	}	

}